package be.artesis.titamo.importer;

import java.io.IOException;
import java.sql.SQLException;
import java.util.prefs.Preferences;

import be.artesis.titamo.exceptions.DriverNotFoundException;
import be.artesis.titamo.exceptions.InterfaceNotFoundException;
import be.artesis.titamo.exceptions.TimeTableParserErrors;
import be.artesis.titamo.exceptions.ToleranceReachedException;
import be.artesis.titamo.io.SQLDatabase;
import be.artesis.titamo.io.TimeTableDataFile;

public abstract class ImporterInterface implements ProgressObserver
{
	// PREFERENCES
	protected Preferences prefs;
	
	// DB Connection Options
	protected String 	connectionString;
	protected int 		dbSystemIndex;
	protected String 	username;
	protected String 	password;
	
	// Import Options
	protected String 	filepath;
	protected String 	delimiter;
	protected String 	subdelimiter;
	protected boolean 	forceImport;
	protected int 		errorTolerance;
	
	// DB Content Options
	protected boolean 	clearDB;
	protected String 	tableName;
	
	// Progress Information handling
	protected abstract void printProgressInfo(String message);
	
	// Error Handling
	protected abstract void handleIOException(IOException e);
	protected abstract void handleTableParserErrors(TimeTableParserErrors e);
	protected abstract void handleSQLException(SQLException e);
	protected abstract void handleDriverNotFoundException(DriverNotFoundException e);
	protected abstract void handleToleranceReachedException(ToleranceReachedException e);
	protected abstract void handleInterfaceNotFoundException(InterfaceNotFoundException e);
	
	// Progress Status handling
	protected abstract void progressUpdate(int percent);
	
	// Interface Starter
	protected abstract boolean preRun();
	protected abstract void postRun();
	
	public ImporterInterface()
	{
		prefs = Preferences.userNodeForPackage(ImporterInterface.class);
		this.loadPreferences();
	}
	
	public void run()
	{
		if (!preRun()) return;
		startImportProcess();
		postRun();
	}
	
	private void startImportProcess()
	{
		printProgressInfo("Importing Started...");
		TimeTableDataFile data = new TimeTableDataFile(filepath.trim(), delimiter, subdelimiter);
		SQLDatabase db = new SQLDatabase(SQLDatabase.DB_DRIVERS[dbSystemIndex], connectionString.trim(), username.trim(), password, tableName.trim());
		
		db.registerObserver(this);
		data.registerObserver(this);
		
		try {
			printProgressInfo("Parsing file...");
			
			TimeTableParserErrors parserErrors = data.parse(errorTolerance);
			
			if ((parserErrors != null))
			{
				handleTableParserErrors(parserErrors);
				if (!forceImport) {
					return;
				}
			}
			
			if (clearDB)
			{
				printProgressInfo("Clearing the timetable...");
				db.dropTimeTable();
				db.createTimeTable(data);
			}
			
			printProgressInfo("Adding records to database...");
			
			db.fillTimeTable(data);
			
			printProgressInfo("Finished!");
			
			saveConnectionString();
			
		} catch (IOException e) {
			handleIOException(e);
			//importLabel.setText("Some errors occurred during installation");
		} catch (SQLException e) {
			handleSQLException(e);
		} catch (DriverNotFoundException e) {
			handleDriverNotFoundException(e);
		} catch (ToleranceReachedException e) {
			handleToleranceReachedException(e);
		} catch (InterfaceNotFoundException e) {
			handleInterfaceNotFoundException(e);
		}
	}
	
	public void update(int percentage) {
		progressUpdate(percentage);
	}
	
	protected void loadPreferences()
	{
		//if (prefs == null) System.out.println("told you so!");
		clearDB = prefs.get(InterfaceConst.BasicPref.TAG_CLEARDB, InterfaceConst.BasicPref.PREF_NOTFOUND).equals("true");
		delimiter = prefs.get(InterfaceConst.BasicPref.TAG_DELIMITER, InterfaceConst.BasicPref.PREF_NOTFOUND);
		subdelimiter = prefs.get(InterfaceConst.BasicPref.TAG_SUBDELIMITER, InterfaceConst.BasicPref.PREF_NOTFOUND);
		//serverDBSystemField.setText(prefs.get(InterfaceConst.Pref.TAG_DBSYSTEM, InterfaceConst.Pref.PREF_NOTFOUND));
		
		dbSystemIndex = prefs.getInt(InterfaceConst.BasicPref.TAG_DBSYSTEM, 0);
		
		filepath = prefs.get(InterfaceConst.BasicPref.TAG_FILE, InterfaceConst.BasicPref.PREF_NOTFOUND);
		
		connectionString = prefs.get(InterfaceConst.BasicPref.TAG_URL, InterfaceConst.BasicPref.PREF_NOTFOUND);
		tableName = prefs.get(InterfaceConst.BasicPref.TAG_DBTABLE, InterfaceConst.BasicPref.PREF_NOTFOUND);
		
		username = prefs.get(InterfaceConst.BasicPref.TAG_DBUSER, InterfaceConst.BasicPref.PREF_NOTFOUND);
		password = prefs.get(InterfaceConst.BasicPref.TAG_DBPASSWORD, InterfaceConst.BasicPref.PREF_NOTFOUND);
		
		forceImport = prefs.get(InterfaceConst.BasicPref.TAG_FORCEIMPORT, InterfaceConst.BasicPref.PREF_NOTFOUND).equals("true");
		errorTolerance = prefs.getInt(InterfaceConst.BasicPref.TAG_ERRORTOLERANCE, 0);
		
		
		
		//System.out.println(errorTolerance);
	}
	
	protected void savePreferences()
	{
		prefs.put(InterfaceConst.BasicPref.TAG_DELIMITER, delimiter);
		prefs.put(InterfaceConst.BasicPref.TAG_SUBDELIMITER, subdelimiter);
		prefs.putInt(InterfaceConst.BasicPref.TAG_DBSYSTEM, dbSystemIndex);
		prefs.put(InterfaceConst.BasicPref.TAG_DBUSER, username);
		prefs.put(InterfaceConst.BasicPref.TAG_DBPASSWORD, password);
		prefs.put(InterfaceConst.BasicPref.TAG_FILE, filepath);
		prefs.put(InterfaceConst.BasicPref.TAG_URL, connectionString);
		prefs.put(InterfaceConst.BasicPref.TAG_DBTABLE, tableName);
		prefs.putInt(InterfaceConst.BasicPref.TAG_ERRORTOLERANCE, errorTolerance);
		if (clearDB) prefs.put(InterfaceConst.BasicPref.TAG_CLEARDB, "true");
		else prefs.put(InterfaceConst.BasicPref.TAG_CLEARDB, "false");
		if (forceImport) prefs.put(InterfaceConst.BasicPref.TAG_FORCEIMPORT, "true");
		else prefs.put(InterfaceConst.BasicPref.TAG_FORCEIMPORT, "false");
		//System.out.println(charArrayToString(userPasswordField.getPassword()).length());
		//System.out.println(charArrayToString(userPasswordField.getPassword()));
	}
	
	private void saveConnectionString()
	{
		prefs.put(InterfaceConst.BasicPref.TAG_URL, connectionString);
	}
}
